home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr49 / pgp23src.zip / MORE.C < prev    next >
C/C++ Source or Header  |  1993-05-18  |  12KB  |  483 lines

  1. /*    more.c  - Unix-style "more" paging output for PGP.
  2.     PGP: Pretty Good(tm) Privacy - public key cryptography for the masses.
  3.  
  4.     (c) Copyright 1990-1992 by Philip Zimmermann.  All rights reserved.
  5.     The author assumes no liability for damages resulting from the use
  6.     of this software, even if the damage results from defects in this
  7.     software.  No warranty is expressed or implied.
  8.  
  9.     All the source code Philip Zimmermann wrote for PGP is available for
  10.     free under the "Copyleft" General Public License from the Free
  11.     Software Foundation.  A copy of that license agreement is included in
  12.     the source release package of PGP.  Code developed by others for PGP
  13.     is also freely available.  Other code that has been incorporated into
  14.     PGP from other sources was either originally published in the public
  15.     domain or was used with permission from the various authors.  See the
  16.     PGP User's Guide for more complete information about licensing,
  17.     patent restrictions on certain algorithms, trademarks, copyrights,
  18.     and export controls.  
  19. */
  20.  
  21. #include <ctype.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #ifdef UNIX
  26. #include <sys/types.h>
  27. #include "system.h"
  28. #endif
  29. #ifdef sco
  30. #include <sys/stream.h>
  31. #include <sys/ptem.h>
  32. FILE *popen();
  33. #endif
  34. #include "mpilib.h"
  35. #include "language.h"
  36. #include "fileio.h"
  37. #include "pgp.h"
  38. #include "more.h"
  39. #include "charset.h"
  40.  
  41. #ifdef MSDOS
  42. #ifndef __GO32__
  43. #include <conio.h>
  44. #endif
  45. #define DEFAULT_LINES    25    /* MSDOS actually has a 25-line screen */
  46. #else
  47. #define DEFAULT_LINES    24
  48. #endif /* MSDOS */
  49. #define DEFAULT_COLUMNS    80
  50.  
  51. static int screen_lines = DEFAULT_LINES, screen_columns = DEFAULT_COLUMNS;
  52.  
  53. #define TAB        0x09        /* ASCII tab char */
  54. #define CR        '\r'        /* Carriage return char */
  55. #define LF        '\n'        /* Linefeed */
  56.  
  57. /* Get the screen size for 'more'.  The environment variables $LINES and
  58.    $COLUMNS will be used if they exist.  If not, then the TIOCGWINSZ call to
  59.    ioctl() is used (if it is defined).  If not, then the TIOCGSIZE call to
  60.    ioctl() is used (if it is defined).  If not, then the WIOCGETD call to
  61.    ioctl() is used (if it is defined).  If not, then get the info from
  62.    terminfo/termcap (if it is there).  Otherwise, assume we have a 24x80
  63.    model 33.
  64.  
  65.    That was for Unix.
  66.  
  67.    For DOS, just assume 24x80. */
  68.  
  69. #ifdef UNIX
  70. /* Try to access terminfo through the termcap-interface in the curses library
  71.    (which requires linking with -lcurses) or use termcap directly (which
  72.    requires linking with -ltermcap) */
  73.  
  74. #ifndef USE_TERMCAP
  75. #ifdef USE_TERMINFO
  76. #define USE_TERMCAP
  77. #endif
  78. #ifdef USE_CURSES
  79. #define USE_TERMCAP
  80. #endif
  81. #endif
  82.  
  83. #ifdef USE_TERMCAP
  84. #define TERMBUFSIZ    1024
  85. #define UNKNOWN_TERM  "unknown"
  86. #define DUMB_TERMBUF  "dumb:co#80:hc:"
  87.  
  88.   extern int  tgetent(), tgetnum();
  89. #endif
  90.  
  91. /* Try to get TIOCGWINSZ from termios.h, then from sys/ioctl.h */
  92. #ifndef NOTERMIO
  93. #ifdef SVR2
  94. #include <termio.h>
  95. #else
  96. #include <termios.h>
  97. #endif /* SVR2 */
  98. #endif
  99.  
  100. #ifndef SVR2
  101. #ifndef TIOCGWINSZ
  102. #ifndef TIOCGSIZE
  103. #ifndef WIOCGETD
  104. #include <sys/ioctl.h>
  105. #endif /* not WIOCGETD */
  106. #endif /* not TIOCGSIZE */
  107. #endif /* not TIOCGWINSZ */
  108.  
  109. /* If we still dont have TIOCGWINSZ (or TIOCGSIZE) try for WIOCGETD */
  110. #ifndef TIOCGWINSZ
  111. #ifndef TIOCGSIZE
  112. #ifndef WIOCGETD
  113. #include <sgtty.h>
  114. #endif /* not WIOCGETD */
  115. #endif /* not TIOCGSIZE */
  116. #endif /* not TIOCGWINSZ */
  117. #endif /* not SVR2 */
  118. #endif    /* UNIX */
  119.  
  120. static void getScreenSize(void)    /* Rot bilong kargo */
  121. /* Return the screen size */
  122. {
  123.     char *envLines, *envColumns;
  124.     long rowTemp = 0, colTemp = 0;
  125. #ifdef UNIX
  126. #ifdef USE_TERMCAP
  127.     char termBuffer[TERMBUFSIZ], *termInfo;
  128. #endif
  129. #ifdef TIOCGWINSZ
  130.     struct winsize windowInfo;
  131. #else
  132. #ifdef TIOCGSIZE
  133.     struct ttysize windowInfo;
  134. #else
  135. #ifdef WIOCGETD
  136.       struct uwdata windowInfo;
  137. #endif /* WIOCGETD */
  138. #endif /* TIOCGSIZE */
  139. #endif /* TIOCGWINSZ */
  140.  
  141.     /* Make sure that we're outputting to a terminal */
  142.     if (!isatty(fileno(stderr)))
  143.     {
  144.         screen_lines = DEFAULT_LINES;
  145.         screen_columns = DEFAULT_COLUMNS;
  146.         return;
  147.     }
  148.     screen_lines = screen_columns = 0;
  149. #endif    /* UNIX */
  150.  
  151.     /* LINES & COLUMNS environment variables override everything else */
  152.     envLines = getenv("LINES");
  153.     if (envLines != NULL && (rowTemp = atol(envLines)) > 0 )
  154.         screen_lines = (int)rowTemp;
  155.  
  156.     envColumns = getenv("COLUMNS");
  157.     if (envColumns != NULL && (colTemp = atol(envColumns)) > 0 )
  158.         screen_columns = (int)colTemp;
  159.  
  160. #ifdef UNIX
  161. #ifdef TIOCGWINSZ
  162.     /* See what ioctl() has to say (overrides terminfo & termcap) */
  163.     if ((!screen_lines || !screen_columns) && ioctl(fileno(stderr),TIOCGWINSZ,&windowInfo) != -1)
  164.     {    if (!screen_lines && windowInfo.ws_row > 0)
  165.             screen_lines = (int)windowInfo.ws_row;
  166.  
  167.         if (!screen_columns && windowInfo.ws_col > 0 )
  168.             screen_columns = (int)windowInfo.ws_col;
  169.     }
  170. #else
  171. #ifdef TIOCGSIZE
  172.     /* See what ioctl() has to say (overrides terminfo & termcap) */
  173.     if ((!screen_lines || !screen_columns) && ioctl(fileno(stderr),TIOCGSIZE,&windowInfo) != -1)
  174.     {    if (!screen_lines && windowInfo.ts_lines > 0)
  175.             screen_lines = (int)windowInfo.ts_lines;
  176.  
  177.         if (!screen_columns && windowInfo.ts_cols > 0)
  178.             screen_columns = (int)windowInfo.ts_cols;
  179.     }
  180. #else
  181. #ifdef WIOCGETD
  182.     /* See what ioctl() has to say (overrides terminfo & termcap) */
  183.     if ((!screen_lines || !screen_columns) && ioctl(fileno(stderr),WIOCGETD,&windowInfo) != -1)
  184.     {    if (!screen_lines && windowInfo.uw_height > 0)
  185.             screen_lines = (int)(windowInfo.uw_height / windowInfo.uw_vs);
  186.  
  187.         if (!screen_columns && windowInfo.uw_width > 0)
  188.             screen_columns = (int)(windowInfo.uw_width / windowInfo.uw_hs);
  189.     }    /* You are in a twisty maze of standards, all different */
  190. #endif
  191. #endif
  192. #endif
  193.  
  194. #ifdef USE_TERMCAP
  195.     /* See what terminfo/termcap has to say */
  196.     if (!screen_lines || !screen_columns)
  197.     {    if ((termInfo = getenv("TERM")) == (char *)NULL)
  198.             termInfo = UNKNOWN_TERM;
  199.  
  200.         if ((tgetent(termBuffer, termInfo) <= 0))
  201.             strcpy(termBuffer,DUMB_TERMBUF);
  202.  
  203.         if (!screen_lines && (rowTemp = tgetnum("li")) > 0)
  204.                 screen_lines = (int)rowTemp;
  205.  
  206.         if (!screen_columns && (colTemp = tgetnum("co")) > 0)
  207.                 screen_columns = (int)colTemp;
  208.     }
  209. #endif
  210.     if (screen_lines == 0)            /* nothing worked, use defaults */
  211.         screen_lines = DEFAULT_LINES;
  212.     if (screen_columns == 0)
  213.         screen_columns = DEFAULT_COLUMNS;
  214. #endif    /* UNIX */
  215. }
  216.  
  217. /* Certain systems need to go into a "break" mode */
  218. #ifdef UNIX
  219. #define    NEEDBREAK
  220. #endif
  221. #ifdef AMIGA
  222. #define NEEDBREAK
  223. #endif
  224. #ifdef ATARI
  225. #define reverse_attr()        printf("\033p")
  226. #define norm_attr()            printf("\033q")
  227. #else
  228. #define reverse_attr()
  229. #define norm_attr()
  230. #endif
  231.  
  232.  
  233. #ifdef VMS
  234. char pager[80] = "Type/Page";    /* default pager for VMS */
  235. #else    /* not VMS */
  236. char pager[80] = "";
  237. #endif    /* not VMS */
  238.  
  239.  
  240. int more_file(char *fileName)
  241. /* Blort a file to the screen with page breaks, intelligent handling of line
  242.    terminators, truncation of overly long lines, and zapping of illegal
  243.    chars */
  244. {
  245.     FILE *inFile;
  246.     int lines = 0,ch,i,chars = 0, c;
  247.     long fileLen;
  248.     char cmd[MAX_PATH];
  249.     char buf[16];
  250.     int lineno;
  251.     char *p;
  252.  
  253.     if ((inFile = fopen(fileName,FOPRBIN)) == NULL)
  254.         /* Can't see how this could fail since we just created the file */
  255.         return(-1);
  256.  
  257.     fread(buf, 1, 16, inFile);
  258.     if (compressSignature( (byte *) buf) >= 0)
  259.     {    fprintf(pgpout, PSTR("\n\007File '%s' is not a text file; cannot display.\n"),
  260.                     fileName);
  261.         return(-1);
  262.     }
  263.  
  264.     /* PAGER set in config.txt overrides environment variable, 
  265.         set PAGER in config.txt to 'pgp' to use builtin pager */
  266.     if (pager[0] == '\0')
  267.     {
  268.         if ((p = getenv("PAGER")) != NULL)
  269.             strncpy(pager, p, sizeof(pager) - 1);
  270.     }
  271.     if (strcmp(pager, "cat") == 0)
  272.     {    fclose(inFile);
  273.         writePhantomOutput(fileName);
  274.         return 0;
  275.     }
  276.  
  277.     /* Use built-in pager if PAGER is not set or if this is for your eyes only,
  278.        this currently doesn't work, the _CONSOLE filename isn't used as the real
  279.        filename anymore */
  280.     if ((strcmp(fileName,CONSOLE_FILENAME) != 0)
  281.         && (strlen(pager) != 0) && strcmp("pgp", pager))
  282.     {
  283.         fclose(inFile);
  284. #ifdef UNIX
  285.         if (strchr(fileName, '\'') != NULL)
  286.             return(-1);
  287.         sprintf(cmd, "%s '%s'", pager, fileName);
  288. #else
  289.         sprintf(cmd, "%s %s", pager, fileName);
  290. #ifdef MSDOS
  291.         for (p = cmd; *p; ++p)
  292.             if (*p == '/')
  293.                 *p = '\\';
  294. #endif
  295. #endif
  296.         fflush(pgpout);
  297.         return(system(cmd));
  298.     }
  299.  
  300. #ifdef UNIX
  301.     if (!isatty(fileno(stdout)))
  302.     {    fclose(inFile);
  303.         writePhantomOutput(fileName);
  304.         return 0;
  305.     }
  306. #endif /* UNIX */
  307.  
  308.     getScreenSize();
  309.  
  310.     /* Get file length */
  311.     fseek(inFile,0L,SEEK_END);
  312.     fileLen = ftell(inFile);
  313.     rewind(inFile);
  314.     lineno = 1;
  315.  
  316. #ifdef NEEDBREAK
  317.     ttycbreak();
  318. #endif
  319.     putchar('\n');
  320.     while (TRUE)
  321.     {   ch = getc(inFile);
  322.         if (ch == LF)
  323.         {   lines++;
  324.             putchar('\n');
  325.             chars = 0;
  326.             ++lineno;
  327.         }
  328.         else
  329.             if (ch == CR)
  330.             {   lines++;
  331.                 putchar('\n');
  332.                 chars = 0;
  333.                 ++lineno;
  334.  
  335.                 /* Skip following LF if there is one */
  336.                 if ((ch = getc(inFile)) != LF && ch != EOF)
  337.                     ungetc(ch,inFile);
  338.             }
  339.             else
  340.                 if (((unsigned char) ch >= ' ' && ch != EOF) || ch == TAB)
  341.                 {   /* Legal char or tab, print it */
  342.                     putchar(ch);
  343.                     chars += (ch == TAB) ? 8 : 1;
  344.                 }
  345.  
  346.         /* If we've reach the max.no of columns we can handle, skip the
  347.            rest of the line */
  348.         if (chars == screen_columns - 1)
  349.         {    chars = 0;
  350.             while ((ch = getc(inFile)) != CR && ch != LF && ch != EOF )
  351.                 ;
  352.             if (ch != EOF)
  353.                 ungetc(ch,inFile);
  354.         }
  355.  
  356.         /* If we've reached the max.no of rows we can handle, wait for the
  357.            user to hit a key */
  358.         while (ch == EOF || lines == screen_lines - 1)
  359.         {    /* Print prompt at end of screen */
  360.             reverse_attr();
  361.             if (ch == EOF)
  362.                 printf(PSTR("\nDone...hit any key\r"));
  363.             else
  364.                 printf(PSTR("More -- %d%% -- Hit space for next screen, Enter for new line, 'Q' to quit --\r"),
  365.                     ( 100 * ftell( inFile ) ) / fileLen );
  366.             norm_attr();
  367.             fflush(stdout);
  368.             c = getch();
  369.             c = to_upper(c);
  370.  
  371.             /* Blank out prompt */
  372.             for (i=0; i<79; i++)
  373.                 putchar(' ');
  374.             putchar('\r');
  375.             fflush(stdout);
  376.             if (c == 'B' && lineno > screen_lines)        /* go Back a page */
  377.             {    int seek_line = lineno - 2*screen_lines + 3;
  378.                 lineno = 1;
  379.                 rewind(inFile);
  380.                 if (seek_line > 1)
  381.                 {    printf("...skipping\n");
  382.                     while ((ch = getc(inFile)) != EOF)
  383.                         if (ch == '\n')
  384.                             if (++lineno == seek_line)
  385.                                 break;
  386.                 }
  387.                 ch = '\0';
  388.                 lines = 0;
  389.             }
  390.             else
  391.             {    if (c == 'Q' || ch == EOF)
  392.                     goto done;
  393.                 if (c == ' ' || c == '\n' || c == '\r' || c == 'J')
  394.                     lines -= (c == ' ') ? screen_lines - 2 : 1;    /* Do n more lines */
  395.             }
  396.         }
  397.     }
  398. done:
  399. #ifdef NEEDBREAK
  400.     ttynorm();
  401. #endif
  402.     fclose(inFile);
  403.     return(0);
  404. } /* more_file */
  405.  
  406.  
  407. /*
  408.  * open_more() and close_more() redirect pgpout to the pager.
  409.  *
  410.  */
  411.  
  412. static char *mfile = NULL;
  413. static boolean piping = FALSE;
  414. static FILE *savepgpout;
  415.  
  416.  
  417. int
  418. open_more(void)
  419. {
  420. #ifdef UNIX
  421.     char *p;
  422. #endif
  423.  
  424.     if (mfile || piping)
  425.         close_more();
  426.  
  427.     savepgpout = pgpout;
  428. #ifdef UNIX
  429.     fflush(pgpout);
  430.     if (pager[0] == '\0')
  431.     {
  432.         if ((p = getenv("PAGER")) != NULL)
  433.             strncpy(pager, p, sizeof(pager) - 1);
  434.     }
  435.     /* Use built-in pager if PAGER is not set or set to "pgp" */
  436.     if ((strlen(pager) != 0) && strcmp("pgp", pager))
  437.     {
  438.         if ((pgpout = popen(pager, "w")) != NULL)
  439.         {    piping = TRUE;
  440.             return 0;
  441.         }
  442.         perror("popen");
  443.         pgpout = savepgpout;
  444.     }
  445. #endif
  446.     if ((mfile = tempfile(TMP_TMPDIR|TMP_WIPE)) == NULL)
  447.         return -1;
  448.     if ((pgpout = fopen(mfile, FOPWTXT)) == NULL)
  449.     {
  450.         pgpout = savepgpout;
  451.         rmtemp(mfile);
  452.         return -1;
  453.     }
  454.     /* user will not see anything until close_more() is called */
  455.     fprintf(savepgpout,PSTR("Just a moment..."));
  456.     fflush(savepgpout);
  457.     return 0;
  458. }
  459.  
  460. int
  461. close_more(void)
  462. {
  463.     if (!mfile && !piping)
  464.         return 0;
  465.  
  466. #ifdef UNIX
  467.     if (piping)
  468.         pclose(pgpout);
  469.     else
  470. #endif
  471.         fclose(pgpout);
  472.     pgpout = savepgpout;
  473.     if (mfile)
  474.     {
  475.         fprintf(pgpout,"\n");
  476.         more_file(mfile);
  477.         rmtemp(mfile);
  478.         mfile = NULL;
  479.     }
  480.     piping = FALSE;
  481.     return 0;
  482. }
  483.